## Libraries used to run all of the functions / code
library(DBI)
library(RPostgres)
library(dplyr)
library(ggplot2)
library(patchwork)
library(tidyr)
library(reshape2)
library(cluster)
library(plotly)

Replace This Code With Your Database Details and Postgres User

# Replace with your actual database details
con <- dbConnect(
  RPostgres::Postgres(),
  dbname = "DataManagement_Database_Project",   # Name of the database
  host = "localhost",              # For local database
  port = 5432,                     # Default PostgreSQL port
  user = "[INSERT_USERNAME]",          # Your PostgreSQL username
  password = "[INSERT_PASSWORD]"       # Your PostgreSQL password
)

Viewing the Available Tables within the Database

dbListTables(con)
 [1] "activity"    "bvp"         "dexcom"      "eda"         "food_log"    "hr"          "ibi"         "nutrition"  
 [9] "participant" "temp"       

Example of Using a Query to Pull Table Data

# A sample that lets you pull data as a table directly into R for easy viewing
two_activity <- dbGetQuery(con, "SELECT * FROM get_participant_activity_data(2);")
two_food <- dbGetQuery(con, "SELECT * FROM get_participant_food_data(2);")
participant <- dbGetQuery(con, "SELECT * FROM participant")
# Listing the current participant IDs
print(participant)

Functions Made with Tables Loaded into R first

Run the Function to Graph


## EXAMPLE and USED EXAMPLE BELOW: 

#plot_glucose_readings(
# dataset_name,
# food_log_datetime_clean = "time on the food log for reference",
# interval before : [sec],
# interval after: [sec] )

# The blue segmented line is the food log datetime that you chose, the purple segments are other meals that occur in the timeline
plot_glucose_readings(
  two_food, 
  food_log_datetime_clean = "2020-02-22 16:08:00", # choose a food_log datetime reference
  interval_before = 1800, # seconds
  interval_after = 18000 # seconds
)
[1] "Additional meals identified (marked in purple lines):"
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
Please use the `linewidth` argument instead.

Checking out Glucose Levels associated with Magnitudes of Activity

# Example usage
# Assuming `two_activity` is the loaded dataset:
analyze_magnitude_glucose(two_activity, bin_width = 10)

Graphing Glucose Levels with activity intensity / magnitude associated - a notable dip can be seen in this portion where high activity led to some drops in glucose mg/dl

# Example usage
#glucose_v_activity([dataset], "[datetime before]", "[datetime after]")

glucose_v_activity(two_activity, "2020-02-21 13:08:36", "2020-02-21 16:41:32")

Functions That Can be Used Dynamically (Queries and Analysis are performed in a single function!)

Using the Function to Import a Range of Graphs and Viewing them 1 at a Time

food_plots[["2"]] # View plots for participant 2

Code That Can be Run Straight Away to Plot the Listed Participants Graphs Above

  • Great for comparing 2 participants or grabbing a large amount of graphs for quick reference
  • Set to resize horizontally based off the number of plots
### Showing a combined plot if we wish to see everyone's data in a chunk

for (i in seq_along(food_plots)) {
  food_plots[[i]] <- food_plots[[i]] & theme_minimal(base_size = 10)
}

combined_plot <- wrap_plots(food_plots, ncol = length(food_plots)) +
  plot_layout(guides = "collect") +
  plot_annotation(title = "Food Analysis Across Participants")

combined_plot

Single Correlation Heatmap Example


# Example Usage
participant_ids <- c(2, 4, 12)
corr_results <- generate_corrMatrix(participant_ids, con)

# View heatmap for participant 2
corr_results[["2"]]$heatmap


# Lets you see the raw numeric inputs
corr_results[["12"]]$correlation_matrix 
                         glucose_value_mgdl avg_magnitude  average_hr activity_intensity_score
glucose_value_mgdl               1.00000000    0.02669356 -0.05655279               -0.0486901
avg_magnitude                    0.02669356    1.00000000  0.02658563                0.2524123
average_hr                      -0.05655279    0.02658563  1.00000000                0.9739883
activity_intensity_score        -0.04869010    0.25241227  0.97398831                1.0000000

Multiple Correlation Heatmap Example (This Code Can be Run Un-Edited)

  • Lets you compare 2 participants quickly ideally, but can be scaled up to grab plots en masse
  • Scales Vertically dependant on the number of participants for organization
# Adjust themes of heatmaps in corr_results
for (i in seq_along(corr_results)) {
  corr_results[[i]]$heatmap <- corr_results[[i]]$heatmap + theme_minimal(base_size = 8)
}

# Extract and combine heatmaps
combined_plot <- wrap_plots(
  lapply(corr_results, function(x) x$heatmap),
  nrow = length(corr_results)
) +
  plot_layout(guides = "collect") +
  plot_annotation(title = "Correlation Heatmaps Across Participants")

# Display the combined plot
combined_plot

Dynamic Clustering Function for activity data (glucose vs magnitude pictured)

  • The Variables can be adjusted to use any of the relationships listed prior for the numeric data
  • The clusters are made through K-means clustering and works with 2 or more variables at a time
cluster_results <- activity_clustering(4, con, k = 3, average_hr, glucose_value_mgdl )

# View glucose comparison (if applicable)
cluster_results$cluster_summary

# Visualize clustering
cluster_results$cluster_plot

Peak Analysis using procedural graph generation based off a participant input

  • A participant can be analyzed with a chosen threshold of their activity score
    • Peaks based off this threshold will be converted to graphs with a window from start of the peak to a chosen duration in hours
  • The generated graph works best in R where the HTML can be viewed in a cleaner format.
    • The plotly package allows scrolling between the peaks to conveniently see notable regions
LS0tDQp0aXRsZTogIk5vdGFibGUgRnVuY3Rpb25zIFVzZWQiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCg0KLS0tDQoNCmBgYHtyfQ0KIyMgTGlicmFyaWVzIHVzZWQgdG8gcnVuIGFsbCBvZiB0aGUgZnVuY3Rpb25zIC8gY29kZQ0KbGlicmFyeShEQkkpDQpsaWJyYXJ5KFJQb3N0Z3JlcykNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBhdGNod29yaykNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShjbHVzdGVyKQ0KbGlicmFyeShwbG90bHkpDQpgYGANCg0KIyMjIFJlcGxhY2UgVGhpcyBDb2RlIFdpdGggWW91ciBEYXRhYmFzZSBEZXRhaWxzIGFuZCBQb3N0Z3JlcyBVc2VyDQotIE5PVEU6IEZPUiB3aW5kb3dzIHN1YnN5c3RlbSBsaW51eCB1c2VycyAoVUJVTlRVKSB0aGUgdWJ1bnR1IHRlcm1pbmFsIHVzZWQgdG8gaW5zdGFsbCAvIHNldHVwIHBvc3RncmVzIG11c3QgYmUgcnVubmluZyB0byBjb25uZWN0IHRvIHlvdXIgZGF0YWJhc2UNCmBgYHtyfQ0KIyBSZXBsYWNlIHdpdGggeW91ciBhY3R1YWwgZGF0YWJhc2UgZGV0YWlscw0KY29uIDwtIGRiQ29ubmVjdCgNCiAgUlBvc3RncmVzOjpQb3N0Z3JlcygpLA0KICBkYm5hbWUgPSAiRGF0YU1hbmFnZW1lbnRfRGF0YWJhc2VfUHJvamVjdCIsICAgIyBOYW1lIG9mIHRoZSBkYXRhYmFzZQ0KICBob3N0ID0gImxvY2FsaG9zdCIsICAgICAgICAgICAgICAjIEZvciBsb2NhbCBkYXRhYmFzZQ0KICBwb3J0ID0gNTQzMiwgICAgICAgICAgICAgICAgICAgICAjIERlZmF1bHQgUG9zdGdyZVNRTCBwb3J0DQogIHVzZXIgPSAiW0lOU0VSVF9VU0VSTkFNRV0iLCAgICAgICAgICAjIFlvdXIgUG9zdGdyZVNRTCB1c2VybmFtZQ0KICBwYXNzd29yZCA9ICJbSU5TRVJUX1BBU1NXT1JEXSIgICAgICAgIyBZb3VyIFBvc3RncmVTUUwgcGFzc3dvcmQNCikNCg0KYGBgDQoNCg0KIyMjIFZpZXdpbmcgdGhlIEF2YWlsYWJsZSBUYWJsZXMgd2l0aGluIHRoZSBEYXRhYmFzZQ0KYGBge3J9DQpkYkxpc3RUYWJsZXMoY29uKQ0KYGBgDQojIyMgRXhhbXBsZSBvZiBVc2luZyBhIFF1ZXJ5IHRvIFB1bGwgVGFibGUgRGF0YQ0KYGBge3J9DQojIEEgc2FtcGxlIHRoYXQgbGV0cyB5b3UgcHVsbCBkYXRhIGFzIGEgdGFibGUgZGlyZWN0bHkgaW50byBSIGZvciBlYXN5IHZpZXdpbmcNCnR3b19hY3Rpdml0eSA8LSBkYkdldFF1ZXJ5KGNvbiwgIlNFTEVDVCAqIEZST00gZ2V0X3BhcnRpY2lwYW50X2FjdGl2aXR5X2RhdGEoMik7IikNCnR3b19mb29kIDwtIGRiR2V0UXVlcnkoY29uLCAiU0VMRUNUICogRlJPTSBnZXRfcGFydGljaXBhbnRfZm9vZF9kYXRhKDIpOyIpDQpwYXJ0aWNpcGFudCA8LSBkYkdldFF1ZXJ5KGNvbiwgIlNFTEVDVCAqIEZST00gcGFydGljaXBhbnQiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBMaXN0aW5nIHRoZSBjdXJyZW50IHBhcnRpY2lwYW50IElEcw0KcHJpbnQocGFydGljaXBhbnQpDQpgYGANCiMgRnVuY3Rpb25zIE1hZGUgd2l0aCBUYWJsZXMgTG9hZGVkIGludG8gUiBmaXJzdA0KLSBUaGlzIHdhcyBkb25lIHdpdGggdGhlIGludGVudGlvbiBvZiBsZXR0aW5nIHRoZSB1c2VyIHNlZSB0aGUgdGFibGVzIGRhdGEgZmlyc3QgdG8gc2VlIGluZm8gbGlrZSBub3RhYmxlIGRhdGV0aW1lcywgYW5kIG90aGVyIHZhbHVlcyB0byByZWZlcmVuY2UgZm9yIHRoZWlyIHVzYWdlIG9mIHRoZXNlIGZ1bmN0aW9ucw0KYGBge3IsIGVjaG89RkFMU0V9DQpwbG90X2dsdWNvc2VfcmVhZGluZ3MgPC0gZnVuY3Rpb24oZGF0YSwgZm9vZF9sb2dfZGF0ZXRpbWVfY2xlYW4sIGludGVydmFsX2JlZm9yZSA9IDE4MDAsIGludGVydmFsX2FmdGVyID0gMTQ0MDApIHsNCiAgIyBDbGVhbiBhbmQgcHJlcGFyZSB0aGUgZGF0YXNldA0KICBkYXRhIDwtIGRhdGEgJT4lDQogICAgbXV0YXRlKA0KICAgICAgIyBSZW1vdmUgdW5kZXJzY29yZSBhbmQgc3Vic2VxdWVudCBpbmZvcm1hdGlvbiBmcm9tIElEcw0KICAgICAgZGV4Y29tX2lkX2NsZWFuID0gc3ViKCJfLioiLCAiIiwgZGV4Y29tX2lkKSwNCiAgICAgIGZvb2RfbG9nX2lkX2NsZWFuID0gc3ViKCJfLioiLCAiIiwgZm9vZF9sb2dfaWQpLA0KICAgICAgDQogICAgICAjIENvbnZlcnQgY2xlYW5lZCBJRHMgdG8gZGF0ZXRpbWUgZm9ybWF0DQogICAgICBkZXhjb21fZGF0ZXRpbWVfY2xlYW4gPSBhcy5QT1NJWGN0KGRleGNvbV9pZF9jbGVhbiwgZm9ybWF0ID0gIiVZLSVtLSVkICVIOiVNOiVTIiksDQogICAgICBmb29kX2xvZ19kYXRldGltZV9jbGVhbiA9IGFzLlBPU0lYY3QoZm9vZF9sb2dfaWRfY2xlYW4sIGZvcm1hdCA9ICIlWS0lbS0lZCAlSDolTTolUyIpDQogICAgKSAlPiUNCiAgICBtdXRhdGUoDQogICAgICAjIEVuc3VyZSBkYXRldGltZSBjb2x1bW5zIGFyZSBwcm9wZXJseSBwYXJzZWQNCiAgICAgIGRleGNvbV9kYXRldGltZV9jbGVhbiA9IGFzLlBPU0lYY3QoZGV4Y29tX2RhdGV0aW1lX2NsZWFuLCBmb3JtYXQgPSAiJVktJW0tJWQgJUg6JU06JVMiKSwNCiAgICAgIGZvb2RfbG9nX2RhdGV0aW1lX2NsZWFuID0gYXMuUE9TSVhjdChmb29kX2xvZ19kYXRldGltZV9jbGVhbiwgZm9ybWF0ID0gIiVZLSVtLSVkICVIOiVNOiVTIikNCiAgICApDQogIA0KICAjIENvbnZlcnQgaW5wdXQgZGF0ZXRpbWUgdG8gUE9TSVhjdA0KICBmb29kX2xvZ19kYXRldGltZV9jbGVhbiA8LSBhcy5QT1NJWGN0KGZvb2RfbG9nX2RhdGV0aW1lX2NsZWFuLCBmb3JtYXQgPSAiJVktJW0tJWQgJUg6JU06JVMiKQ0KICANCiAgIyBDYWxjdWxhdGUgdGhlIHN0YXJ0IGFuZCBlbmQgb2YgdGhlIGludGVydmFsDQogIGludGVydmFsX3N0YXJ0IDwtIGZvb2RfbG9nX2RhdGV0aW1lX2NsZWFuIC0gaW50ZXJ2YWxfYmVmb3JlDQogIGludGVydmFsX2VuZCA8LSBmb29kX2xvZ19kYXRldGltZV9jbGVhbiArIGludGVydmFsX2FmdGVyDQogIA0KICAjIEZpbHRlciBkYXRhIGZvciBnbHVjb3NlIHJlYWRpbmdzIHdpdGhpbiB0aGUgaW50ZXJ2YWwNCiAgc2VsZWN0ZWRfZGF0YSA8LSBkYXRhICU+JQ0KICAgIGZpbHRlcigNCiAgICAgICFpcy5uYShkZXhjb21fZGF0ZXRpbWVfY2xlYW4pICYNCiAgICAgICFpcy5uYShnbHVjb3NlX3ZhbHVlX21nZGwpICYNCiAgICAgIGRleGNvbV9kYXRldGltZV9jbGVhbiA+PSBpbnRlcnZhbF9zdGFydCAmDQogICAgICBkZXhjb21fZGF0ZXRpbWVfY2xlYW4gPD0gaW50ZXJ2YWxfZW5kDQogICAgKQ0KICANCiAgIyBDaGVjayBpZiB0aGVyZSBhcmUgZ2x1Y29zZSByZWFkaW5ncyBpbiB0aGUgaW50ZXJ2YWwNCiAgaWYgKG5yb3coc2VsZWN0ZWRfZGF0YSkgPiAwKSB7DQogICAgIyBGaW5kIHRoZSBlYXJsaWVzdCBkZXhjb21fZGF0ZXRpbWVfY2xlYW4gYXMgdGhlIHplcm8gcG9pbnQNCiAgICBlYXJsaWVzdF90aW1lIDwtIG1pbihzZWxlY3RlZF9kYXRhJGRleGNvbV9kYXRldGltZV9jbGVhbiwgbmEucm0gPSBUUlVFKQ0KICAgIA0KICAgICMgQ2FsY3VsYXRlIHJlbGF0aXZlIHRpbWUgYmFzZWQgb24gdGhlIGVhcmxpZXN0IGRleGNvbV9kYXRldGltZV9jbGVhbg0KICAgIHNlbGVjdGVkX2RhdGEgPC0gc2VsZWN0ZWRfZGF0YSAlPiUNCiAgICAgIG11dGF0ZShyZWxhdGl2ZV90aW1lID0gYXMubnVtZXJpYyhkaWZmdGltZShkZXhjb21fZGF0ZXRpbWVfY2xlYW4sIGVhcmxpZXN0X3RpbWUsIHVuaXRzID0gIm1pbnMiKSkpDQogICAgDQogICAgIyBDYWxjdWxhdGUgdGhlIHJlbGF0aXZlIHRpbWUgb2YgdGhlIGluaXRpYWwgZm9vZF9sb2dfZGF0ZXRpbWVfY2xlYW4NCiAgICBmb29kX3JlbGF0aXZlX3RpbWUgPC0gYXMubnVtZXJpYyhkaWZmdGltZShmb29kX2xvZ19kYXRldGltZV9jbGVhbiwgZWFybGllc3RfdGltZSwgdW5pdHMgPSAibWlucyIpKQ0KICAgIA0KICAgICMgRmluZCBhZGRpdGlvbmFsIG1lYWxzIHJlZ2lzdGVyZWQgd2l0aGluIHRoZSBpbnRlcnZhbA0KICAgIGFkZGl0aW9uYWxfbWVhbHMgPC0gZGF0YSAlPiUNCiAgICAgIGZpbHRlcigNCiAgICAgICAgIWlzLm5hKGZvb2RfbG9nX2RhdGV0aW1lX2NsZWFuKSAmDQogICAgICAgIGZvb2RfbG9nX2RhdGV0aW1lX2NsZWFuID4gZm9vZF9sb2dfZGF0ZXRpbWVfY2xlYW5bMV0gJiAgIyBDb21wYXJlIGFnYWluc3QgdGhlIG9yaWdpbmFsIGlucHV0DQogICAgICAgIGZvb2RfbG9nX2RhdGV0aW1lX2NsZWFuID49IGludGVydmFsX3N0YXJ0ICYgICAgICAgICAgICAgIyBXaXRoaW4gaW50ZXJ2YWwNCiAgICAgICAgZm9vZF9sb2dfZGF0ZXRpbWVfY2xlYW4gPD0gaW50ZXJ2YWxfZW5kDQogICAgICApICU+JQ0KICAgICAgbXV0YXRlKHJlbGF0aXZlX3RpbWUgPSBhcy5udW1lcmljKGRpZmZ0aW1lKGZvb2RfbG9nX2RhdGV0aW1lX2NsZWFuLCBlYXJsaWVzdF90aW1lLCB1bml0cyA9ICJtaW5zIikpKQ0KICAgIA0KICAgICMgRGVidWc6IFByaW50IGFkZGl0aW9uYWwgbWVhbHMgZm91bmQNCiAgICBpZiAobnJvdyhhZGRpdGlvbmFsX21lYWxzKSA+IDApIHsNCiAgICAgIHByaW50KCJBZGRpdGlvbmFsIG1lYWxzIGlkZW50aWZpZWQgKG1hcmtlZCBpbiBwdXJwbGUgbGluZXMpOiIpDQogICAgICBwcmludChhZGRpdGlvbmFsX21lYWxzKQ0KICAgIH0gZWxzZSB7DQogICAgICBwcmludCgiTm8gYWRkaXRpb25hbCBtZWFscyBpZGVudGlmaWVkLiIpDQogICAgfQ0KICAgIA0KICAgICMgUGxvdCB0aGUgZ2x1Y29zZSB2YWx1ZXMNCiAgICBwbG90IDwtIGdncGxvdChzZWxlY3RlZF9kYXRhLCBhZXMoeCA9IHJlbGF0aXZlX3RpbWUsIHkgPSBnbHVjb3NlX3ZhbHVlX21nZGwpKSArDQogICAgICBnZW9tX2xpbmUoY29sb3IgPSAiYmx1ZSIsIGFscGhhID0gMC4wMSkgKw0KICAgICAgZ2VvbV9wb2ludChjb2xvciA9ICJyZWQiLCBzaXplID0gMSwgYWxwaGEgPSAwLjAyKSArDQogICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBmb29kX3JlbGF0aXZlX3RpbWUsIGNvbG9yID0gInR1cnF1b2lzZSIsIGxpbmV0eXBlID0gImRhc2hlZCIsIGxpbmV3aWR0aCA9IDEuNCkgKw0KICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImdhbSIsIGZvcm11bGEgPSB5IH4gcyh4LCBicyA9ICJjcyIpLCBzZSA9IEZBTFNFLCBjb2xvciA9ICIjMTU2MTZkIiwgc2l6ZSA9IDEuMiwgYWxwaGEgPSAwLjgpICsNCiAgICAgIGxhYnMoDQogICAgICAgIHRpdGxlID0gcGFzdGUoIkdsdWNvc2UgUmVhZGluZ3MgUmVsYXRpdmUgdG8gRm9vZCBMb2cgYXQiLCBmb29kX2xvZ19kYXRldGltZV9jbGVhbiksDQogICAgICAgIHggPSAiVGltZSBTaW5jZSBFYXJsaWVzdCBSZWFkaW5nIChtaW51dGVzKSIsDQogICAgICAgIHkgPSAiR2x1Y29zZSBMZXZlbCAobWcvZEwpIg0KICAgICAgKSArDQogICAgICB0aGVtZV9taW5pbWFsKCkgKw0KICAgICAgdGhlbWUoDQogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JheTk1Iiwgc2l6ZSA9IDAuMSksICAjIE11dGVkIGdyaWRsaW5lcw0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyYXk5NSIsIHNpemUgPSAwLjEpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAgICAgICAgICAgICAgICAgICAgICAgICAjIE5vIG1pbm9yIGdyaWRsaW5lcw0KICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC44KSwgICAgICAjIEFkZCBheGlzIGxpbmVzDQogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgUmVtb3ZlIGZ1bGwgcGFuZWwgYm9yZGVyDQogICAgICApDQogICAgDQogICAgIyBBZGQgdmVydGljYWwgbGluZXMgZm9yIGFkZGl0aW9uYWwgbWVhbHMNCiAgICBpZiAobnJvdyhhZGRpdGlvbmFsX21lYWxzKSA+IDApIHsNCiAgICAgIGZvciAoaSBpbiAxOm5yb3coYWRkaXRpb25hbF9tZWFscykpIHsNCiAgICAgICAgbWVhbF90aW1lIDwtIGFkZGl0aW9uYWxfbWVhbHMkcmVsYXRpdmVfdGltZVtpXQ0KICAgICAgICBwbG90IDwtIHBsb3QgKw0KICAgICAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lYWxfdGltZSwgY29sb3IgPSAicHVycGxlIiwgYWxwaGEgPSAwLjQsIGxpbmV0eXBlID0gImRvdHRlZCIsIHNpemUgPSAxKQ0KICAgICAgfQ0KICAgIH0NCiAgICANCiAgICAjIFByaW50IHRoZSBwbG90DQogICAgcHJpbnQocGxvdCkNCiAgfSBlbHNlIHsNCiAgICBwcmludCgiTm8gbWF0Y2hpbmcgZ2x1Y29zZSByZWFkaW5ncyBmb3VuZCB3aXRoaW4gdGhlIHNwZWNpZmllZCBpbnRlcnZhbC4iKQ0KICB9DQp9DQoNCg0KYGBgDQoNCiMjIyBSdW4gdGhlIEZ1bmN0aW9uIHRvIEdyYXBoDQpgYGB7cn0NCg0KIyMgRVhBTVBMRSBhbmQgVVNFRCBFWEFNUExFIEJFTE9XOiANCg0KI3Bsb3RfZ2x1Y29zZV9yZWFkaW5ncygNCiMgZGF0YXNldF9uYW1lLA0KIyBmb29kX2xvZ19kYXRldGltZV9jbGVhbiA9ICJ0aW1lIG9uIHRoZSBmb29kIGxvZyBmb3IgcmVmZXJlbmNlIiwNCiMgaW50ZXJ2YWwgYmVmb3JlIDogW3NlY10sDQojIGludGVydmFsIGFmdGVyOiBbc2VjXSApDQoNCiMgVGhlIGJsdWUgc2VnbWVudGVkIGxpbmUgaXMgdGhlIGZvb2QgbG9nIGRhdGV0aW1lIHRoYXQgeW91IGNob3NlLCB0aGUgcHVycGxlIHNlZ21lbnRzIGFyZSBvdGhlciBtZWFscyB0aGF0IG9jY3VyIGluIHRoZSB0aW1lbGluZQ0KcGxvdF9nbHVjb3NlX3JlYWRpbmdzKA0KICB0d29fZm9vZCwgDQogIGZvb2RfbG9nX2RhdGV0aW1lX2NsZWFuID0gIjIwMjAtMDItMjIgMTY6MDg6MDAiLCAjIGNob29zZSBhIGZvb2RfbG9nIGRhdGV0aW1lIHJlZmVyZW5jZQ0KICBpbnRlcnZhbF9iZWZvcmUgPSAxODAwLCAjIHNlY29uZHMNCiAgaW50ZXJ2YWxfYWZ0ZXIgPSAxODAwMCAjIHNlY29uZHMNCikNCmBgYA0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KIyBGdW5jdGlvbiB0byBiaW4gbWFnbml0dWRlcyBhbmQgYW5hbHl6ZSBnbHVjb3NlIGxldmVscw0KYW5hbHl6ZV9tYWduaXR1ZGVfZ2x1Y29zZSA8LSBmdW5jdGlvbihkYXRhLCBiaW5fd2lkdGggPSA1KSB7DQogIA0KICAgICMgRW5zdXJlIGF2Z19tYWduaXR1ZGUgaXMgbnVtZXJpYyBhbmQgcmVtb3ZlIE5BIHZhbHVlcw0KICBkYXRhIDwtIGRhdGEgJT4lDQogICAgZmlsdGVyKCFpcy5uYShhdmdfbWFnbml0dWRlKSAmIGlzLmZpbml0ZShhdmdfbWFnbml0dWRlKSkNCiAgDQogICMgQ3JlYXRlIGJpbnMgYmFzZWQgb24gc3BlY2lmaWVkIGJpbiB3aWR0aA0KICBkYXRhIDwtIGRhdGEgJT4lDQogICAgbXV0YXRlKG1hZ25pdHVkZV9iaW4gPSBjdXQoYXZnX21hZ25pdHVkZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoZmxvb3IobWluKGF2Z19tYWduaXR1ZGUsIG5hLnJtID0gVFJVRSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZWlsaW5nKG1heChhdmdfbWFnbml0dWRlLCBuYS5ybSA9IFRSVUUpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBiaW5fd2lkdGgpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkpICU+JQ0KICAgIGdyb3VwX2J5KG1hZ25pdHVkZV9iaW4pICU+JQ0KICAgIHN1bW1hcmlzZShhdmdfZ2x1Y29zZSA9IG1lYW4oZ2x1Y29zZV92YWx1ZV9tZ2RsLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICBjb3VudCA9IG4oKSwNCiAgICAgICAgICAgICAgLmdyb3VwcyA9ICJkcm9wIikNCiAgDQogICMgVmlzdWFsaXphdGlvbg0KICBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBtYWduaXR1ZGVfYmluLCB5ID0gYXZnX2dsdWNvc2UpKSArDQogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic2t5Ymx1ZSIpICsNCiAgICBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgR2x1Y29zZSBMZXZlbHMgYnkgTWFnbml0dWRlIEJpbnMiLA0KICAgICAgICAgeCA9ICJNYWduaXR1ZGUgQmlucyIsDQogICAgICAgICB5ID0gIkF2ZXJhZ2UgR2x1Y29zZSBMZXZlbCAobWcvZEwpIikgKw0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCn0NCg0KYGBgDQoNCiMjIyBDaGVja2luZyBvdXQgR2x1Y29zZSBMZXZlbHMgYXNzb2NpYXRlZCB3aXRoIE1hZ25pdHVkZXMgb2YgQWN0aXZpdHkNCmBgYHtyfQ0KIyBFeGFtcGxlIHVzYWdlDQojIEFzc3VtaW5nIGB0d29fYWN0aXZpdHlgIGlzIHRoZSBsb2FkZWQgZGF0YXNldDoNCmFuYWx5emVfbWFnbml0dWRlX2dsdWNvc2UodHdvX2FjdGl2aXR5LCBiaW5fd2lkdGggPSAxMCkNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCiMgRnVuY3Rpb24gdG8gZmlsdGVyIGJ5IHRpbWUgaW50ZXJ2YWwgYW5kIHBsb3QgZ2x1Y29zZSwgYWN0aXZpdHkgaW50ZW5zaXR5LCBhbmQgYXZlcmFnZSBtYWduaXR1ZGUNCmdsdWNvc2Vfdl9hY3Rpdml0eSA8LSBmdW5jdGlvbihkYXRhLCBzdGFydF90aW1lLCBlbmRfdGltZSkgew0KICANCiAgIyBDb252ZXJ0IGRhdGV0aW1lIHRvIFBPU0lYY3QgZm9yIGZpbHRlcmluZw0KICBkYXRhIDwtIGRhdGEgJT4lDQogICAgbXV0YXRlKGRleGNvbV9kYXRldGltZSA9IGFzLlBPU0lYY3QoZGV4Y29tX2RhdGV0aW1lLCBmb3JtYXQgPSAiJVktJW0tJWQgJUg6JU06JVMiKSkNCiAgDQogICMgRHJvcCByb3dzIHdpdGggTkEgdmFsdWVzIGluIGtleSBjb2x1bW5zDQogIGNsZWFuX2RhdGEgPC0gZGF0YSAlPiUNCiAgICBmaWx0ZXIoIWlzLm5hKGdsdWNvc2VfdmFsdWVfbWdkbCkgJiANCiAgICAgICAgICAgIWlzLm5hKGF2Z19tYWduaXR1ZGUpICYgDQogICAgICAgICAgICFpcy5uYShhY3Rpdml0eV9pbnRlbnNpdHlfc2NvcmUpKQ0KICANCiAgIyBGaWx0ZXIgZGF0YSBiYXNlZCBvbiB0aGUgZ2l2ZW4gdGltZSBpbnRlcnZhbA0KICBmaWx0ZXJlZF9kYXRhIDwtIGNsZWFuX2RhdGEgJT4lDQogICAgZmlsdGVyKGRleGNvbV9kYXRldGltZSA+PSBhcy5QT1NJWGN0KHN0YXJ0X3RpbWUpICYNCiAgICAgICAgICAgZGV4Y29tX2RhdGV0aW1lIDw9IGFzLlBPU0lYY3QoZW5kX3RpbWUpKQ0KICANCiAgIyBDaGVjayBpZiBmaWx0ZXJlZCBkYXRhIGlzIG5vbi1lbXB0eQ0KICBpZiAobnJvdyhmaWx0ZXJlZF9kYXRhKSA9PSAwKSB7DQogICAgc3RvcCgiTm8gZGF0YSBhdmFpbGFibGUgaW4gdGhlIHNlbGVjdGVkIHRpbWUgaW50ZXJ2YWwuIikNCiAgfQ0KICANCiAgIyBNZWx0IGRhdGEgZm9yIHBsb3R0aW5nDQogIHBsb3RfZGF0YSA8LSBmaWx0ZXJlZF9kYXRhICU+JQ0KICAgIHNlbGVjdChkZXhjb21fZGF0ZXRpbWUsIGdsdWNvc2VfdmFsdWVfbWdkbCwgYWN0aXZpdHlfaW50ZW5zaXR5X3Njb3JlLCBhdmdfbWFnbml0dWRlKSAlPiUNCiAgICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGdsdWNvc2VfdmFsdWVfbWdkbCwgYWN0aXZpdHlfaW50ZW5zaXR5X3Njb3JlLCBhdmdfbWFnbml0dWRlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlZhcmlhYmxlIiwgdmFsdWVzX3RvID0gIlZhbHVlIikNCiAgDQogICMgUGxvdCB0aGUgZGF0YQ0KICBnZ3Bsb3QocGxvdF9kYXRhLCBhZXMoeCA9IGRleGNvbV9kYXRldGltZSwgeSA9IFZhbHVlLCBjb2xvciA9IFZhcmlhYmxlKSkgKw0KICAgIGdlb21fbGluZSgpICsNCiAgICBsYWJzKHRpdGxlID0gIkdsdWNvc2UsIEFjdGl2aXR5IEludGVuc2l0eSwgYW5kIE1hZ25pdHVkZSBPdmVyIFRpbWUiLA0KICAgICAgICAgeCA9ICJUaW1lIiwNCiAgICAgICAgIHkgPSAiVmFsdWVzIiwNCiAgICAgICAgIGNvbG9yID0gIk1ldHJpYyIpICsNCiAgICB0aGVtZV9taW5pbWFsKCkgKw0KICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQp9DQoNCmBgYA0KDQpHcmFwaGluZyBHbHVjb3NlIExldmVscyB3aXRoIGFjdGl2aXR5IGludGVuc2l0eSAvIG1hZ25pdHVkZSBhc3NvY2lhdGVkDQogLSBhIG5vdGFibGUgZGlwIGNhbiBiZSBzZWVuIGluIHRoaXMgcG9ydGlvbiB3aGVyZSBoaWdoIGFjdGl2aXR5IGxlZCB0byBzb21lIGRyb3BzIGluIGdsdWNvc2UgbWcvZGwNCmBgYHtyfQ0KIyBFeGFtcGxlIHVzYWdlDQojZ2x1Y29zZV92X2FjdGl2aXR5KFtkYXRhc2V0XSwgIltkYXRldGltZSBiZWZvcmVdIiwgIltkYXRldGltZSBhZnRlcl0iKQ0KDQpnbHVjb3NlX3ZfYWN0aXZpdHkodHdvX2FjdGl2aXR5LCAiMjAyMC0wMi0yMSAxMzowODozNiIsICIyMDIwLTAyLTIxIDE2OjQxOjMyIikNCmBgYA0KDQojIEZ1bmN0aW9ucyBUaGF0IENhbiBiZSBVc2VkIER5bmFtaWNhbGx5IChRdWVyaWVzIGFuZCBBbmFseXNpcyBhcmUgcGVyZm9ybWVkIGluIGEgc2luZ2xlIGZ1bmN0aW9uISkNCi0gT3VyIGZhdm9yaXRlIHBvcnRpb24gb2YgdGhpcyBwcm9qZWN0IHRoYXQgdHJ1bHkgYnVpbGRzIG9mZiB0aGUgaW5pdGlhbCByZWxhdGlvbmFsIGRhdGFiYXNlIGFyY2hpdGVjdHVyZQ0KLSBGdW5jdGlvbnMgbWFkZSBmb3IgcXVlcnlpbmcgdGhlIGRhdGFiYXNlIChmb3IgYWN0aXZpdHkgYW5kIGZvb2QgZGF0YSkgd2VyZSBlbWJlZGRlZCBpbnRvIHRoZXNlIGZ1bmN0aW9ucyB0byBhbGxvdyB2ZXJ5IHNpbXBsZSBpbnB1dHMgdG8gZ2VuZXJhdGUgcGxvdHMgYXMgYSBxdWljayB0b29sIGZvciByYXBpZCBhbmFseXNpcw0KDQpgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQpnZW5lcmF0ZV9mb29kX2FuYWx5c2lzIDwtIGZ1bmN0aW9uKHBhcnRpY2lwYW50X2lkcywgY29uKSB7DQogICMgSW5pdGlhbGl6ZSBhbiBlbXB0eSBsaXN0IHRvIHN0b3JlIGFsbCBwbG90cw0KICBwbG90c19saXN0IDwtIGxpc3QoKQ0KICANCiAgIyBMb29wIHRocm91Z2ggZWFjaCBwYXJ0aWNpcGFudCBJRA0KICBmb3IgKHBhcnRpY2lwYW50X2lkIGluIHBhcnRpY2lwYW50X2lkcykgew0KICAgICMgUXVlcnkgdGhlIGRhdGFiYXNlIGZvciB0aGUgcGFydGljaXBhbnQncyBmb29kIGRhdGENCiAgICBxdWVyeSA8LSBwYXN0ZTAoIlNFTEVDVCAqIEZST00gZ2V0X3BhcnRpY2lwYW50X2Zvb2RfZGF0YSgiLCBwYXJ0aWNpcGFudF9pZCwgIik7IikNCiAgICBmb29kX2RhdGEgPC0gc3VwcHJlc3NNZXNzYWdlcyhkYkdldFF1ZXJ5KGNvbiwgcXVlcnkpKQ0KICAgIA0KICAgICMgRW5zdXJlIGZvb2RfZGF0YSBpcyBub3QgZW1wdHkNCiAgICBpZiAobnJvdyhmb29kX2RhdGEpID09IDApIHsNCiAgICAgIHdhcm5pbmcocGFzdGUoIk5vIGZvb2QgZGF0YSBhdmFpbGFibGUgZm9yIHBhcnRpY2lwYW50IiwgcGFydGljaXBhbnRfaWQpKQ0KICAgICAgbmV4dA0KICAgIH0NCg0KICAgICMgQWdncmVnYXRlIGRhdGEgYnkgJ2Zvb2RfbG9nX2RhdGUnDQogICAgZGFpbHlfdG90YWxzIDwtIHN1cHByZXNzTWVzc2FnZXMoDQogICAgICBmb29kX2RhdGEgJT4lDQogICAgICAgIG11dGF0ZShmb29kX2xvZ19kYXRlID0gYXMuRGF0ZShmb29kX2xvZ19kYXRlKSkgJT4lDQogICAgICAgIGdyb3VwX2J5KGZvb2RfbG9nX2RhdGUpICU+JQ0KICAgICAgICBzdW1tYXJpc2UoDQogICAgICAgICAgdG90YWxfY2Fsb3JpZXMgPSBzdW0oY2Fsb3JpZSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICB0b3RhbF9jYXJicyA9IHN1bSh0b3RhbF9jYXJiLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgIHRvdGFsX3N1Z2FyID0gc3VtKHN1Z2FyLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgIHRvdGFsX2ZpYmVyID0gc3VtKGRpZXRhcnlfZmliZXIsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgdG90YWxfcHJvdGVpbiA9IHN1bShwcm90ZWluLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgIHRvdGFsX2ZhdCA9IHN1bSh0b3RhbF9mYXQsIG5hLnJtID0gVFJVRSkNCiAgICAgICAgKSAlPiUNCiAgICAgICAgdW5ncm91cCgpDQogICAgKQ0KICAgIA0KICAgICMgQ3JlYXRlIGJhciBjaGFydCBmb3IgY2Fsb3JpZXMNCiAgICBjYWxvcmllX3Bsb3QgPC0gZ2dwbG90KGRhaWx5X3RvdGFscywgYWVzKHggPSBmb29kX2xvZ19kYXRlLCB5ID0gdG90YWxfY2Fsb3JpZXMpKSArDQogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjZmM4ZDYyIikgKw0KICAgICAgbGFicyh0aXRsZSA9IHBhc3RlKCJDYWwuIHYgRGF5IChQOiIsIHBhcnRpY2lwYW50X2lkLCAiKSIpLA0KICAgICAgICAgICB4ID0gIkRhdGUiLCB5ID0gIlRvdGFsIENhbG9yaWVzIikgKw0KICAgICAgdGhlbWVfbWluaW1hbCgpICsNCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQogICAgDQogICAgIyBDcmVhdGUgYmFyIGNoYXJ0IGZvciBvdGhlciBudXRyaWVudHMNCiAgICBudXRyaWVudHNfcGxvdCA8LSBzdXBwcmVzc01lc3NhZ2VzKA0KICAgICAgZGFpbHlfdG90YWxzICU+JQ0KICAgICAgICBwaXZvdF9sb25nZXIoY29scyA9IHRvdGFsX2NhcmJzOnRvdGFsX2ZhdCwgbmFtZXNfdG8gPSAiTnV0cmllbnQiLCB2YWx1ZXNfdG8gPSAiVmFsdWUiKSAlPiUNCiAgICAgICAgZ2dwbG90KGFlcyh4ID0gZm9vZF9sb2dfZGF0ZSwgeSA9IFZhbHVlLCBmaWxsID0gTnV0cmllbnQpKSArDQogICAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgICAgICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKw0KICAgICAgICBsYWJzKHRpdGxlID0gcGFzdGUoIk51dHIuIHZzIERheSAoUDoiLCBwYXJ0aWNpcGFudF9pZCwgIikiKSwNCiAgICAgICAgICAgICB4ID0gIkRhdGUiLCB5ID0gIlRvdGFsIFZhbHVlIikgKw0KICAgICAgICB0aGVtZV9taW5pbWFsKCkgKw0KICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KICAgICkNCg0KICAgICMgQ29tYmluZSBwbG90cyBmb3IgdGhlIHBhcnRpY2lwYW50DQogICAgcGxvdHNfbGlzdFtbYXMuY2hhcmFjdGVyKHBhcnRpY2lwYW50X2lkKV1dIDwtIGNhbG9yaWVfcGxvdCAvIG51dHJpZW50c19wbG90DQogIH0NCiAgDQogICMgUmV0dXJuIGFsbCBnZW5lcmF0ZWQgcGxvdHMNCiAgcmV0dXJuKHBsb3RzX2xpc3QpDQp9DQoNCmBgYA0KDQojIyMgVXNpbmcgdGhlIEZ1bmN0aW9uIHRvIEltcG9ydCBhIFJhbmdlIG9mIEdyYXBocyBhbmQgVmlld2luZyB0aGVtIDEgYXQgYSBUaW1lDQpgYGB7ciwgcmVzdWx0cz0naGlkZSd9DQojIEV4YW1wbGUgVXNhZ2U6DQpwYXJ0aWNpcGFudF9pZHMgPC0gYygyLCA0LCAxMikNCmZvb2RfcGxvdHMgPC0gZ2VuZXJhdGVfZm9vZF9hbmFseXNpcyhwYXJ0aWNpcGFudF9pZHMsIGNvbikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsfQ0KZm9vZF9wbG90c1tbIjIiXV0gIyBWaWV3IHBsb3RzIGZvciBwYXJ0aWNpcGFudCAyDQoNCmBgYA0KDQojIyMgQ29kZSBUaGF0IENhbiBiZSBSdW4gU3RyYWlnaHQgQXdheSB0byBQbG90IHRoZSBMaXN0ZWQgUGFydGljaXBhbnRzIEdyYXBocyBBYm92ZQ0KLSBHcmVhdCBmb3IgY29tcGFyaW5nIDIgcGFydGljaXBhbnRzIG9yIGdyYWJiaW5nIGEgbGFyZ2UgYW1vdW50IG9mIGdyYXBocyBmb3IgcXVpY2sgcmVmZXJlbmNlDQotIFNldCB0byByZXNpemUgaG9yaXpvbnRhbGx5IGJhc2VkIG9mZiB0aGUgbnVtYmVyIG9mIHBsb3RzDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMjIyBTaG93aW5nIGEgY29tYmluZWQgcGxvdCBpZiB3ZSB3aXNoIHRvIHNlZSBldmVyeW9uZSdzIGRhdGEgaW4gYSBjaHVuaw0KDQpmb3IgKGkgaW4gc2VxX2Fsb25nKGZvb2RfcGxvdHMpKSB7DQogIGZvb2RfcGxvdHNbW2ldXSA8LSBmb29kX3Bsb3RzW1tpXV0gJiB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEwKQ0KfQ0KDQpjb21iaW5lZF9wbG90IDwtIHdyYXBfcGxvdHMoZm9vZF9wbG90cywgbmNvbCA9IGxlbmd0aChmb29kX3Bsb3RzKSkgKw0KICBwbG90X2xheW91dChndWlkZXMgPSAiY29sbGVjdCIpICsNCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIkZvb2QgQW5hbHlzaXMgQWNyb3NzIFBhcnRpY2lwYW50cyIpDQoNCmNvbWJpbmVkX3Bsb3QNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmdlbmVyYXRlX2NvcnJNYXRyaXggPC0gZnVuY3Rpb24ocGFydGljaXBhbnRfaWRzLCBjb24pIHsNCiAgIyBJbml0aWFsaXplIGEgbGlzdCB0byBzdG9yZSBjb3JyZWxhdGlvbiBtYXRyaWNlcyBhbmQgaGVhdG1hcHMNCiAgcmVzdWx0cyA8LSBsaXN0KCkNCiAgDQogIGZvciAocGFydGljaXBhbnRfaWQgaW4gcGFydGljaXBhbnRfaWRzKSB7DQogICAgIyBRdWVyeSBkYXRhYmFzZSBmb3IgdGhlIHBhcnRpY2lwYW50J3MgYWN0aXZpdHkgZGF0YQ0KICAgIHF1ZXJ5IDwtIHBhc3RlMCgiU0VMRUNUICogRlJPTSBnZXRfcGFydGljaXBhbnRfYWN0aXZpdHlfZGF0YSgiLCBwYXJ0aWNpcGFudF9pZCwgIik7IikNCiAgICBhY3Rpdml0eV9kYXRhIDwtIGRiR2V0UXVlcnkoY29uLCBxdWVyeSkNCiAgICANCiAgICAjIEVuc3VyZSBkYXRhIGlzIG5vdCBlbXB0eQ0KICAgIGlmIChucm93KGFjdGl2aXR5X2RhdGEpID09IDApIHsNCiAgICAgIHdhcm5pbmcocGFzdGUoIk5vIGFjdGl2aXR5IGRhdGEgYXZhaWxhYmxlIGZvciBwYXJ0aWNpcGFudCIsIHBhcnRpY2lwYW50X2lkKSkNCiAgICAgIG5leHQNCiAgICB9DQogICAgDQogICAgIyBTZWxlY3QgcmVsZXZhbnQgY29sdW1ucyBmb3IgY29ycmVsYXRpb24NCiAgICBjb3JyX2RhdGEgPC0gYWN0aXZpdHlfZGF0YSAlPiUNCiAgICAgIHNlbGVjdChnbHVjb3NlX3ZhbHVlX21nZGwsIGF2Z19tYWduaXR1ZGUsIGF2ZXJhZ2VfaHIsIGFjdGl2aXR5X2ludGVuc2l0eV9zY29yZSkgJT4lDQogICAgICBuYS5vbWl0KCkNCiAgICANCiAgICAjIENhbGN1bGF0ZSBjb3JyZWxhdGlvbiBtYXRyaXgNCiAgICBjb3JfbWF0cml4IDwtIGNvcihjb3JyX2RhdGEpDQogICAgDQogICAgIyBNZWx0IHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggZm9yIHBsb3R0aW5nDQogICAgbWVsdGVkX2NvcnIgPC0gbWVsdChjb3JfbWF0cml4KQ0KICAgIA0KICAgICMgR2VuZXJhdGUgaGVhdG1hcA0KICAgIGhlYXRtYXAgPC0gZ2dwbG90KGRhdGEgPSBtZWx0ZWRfY29yciwgYWVzKHggPSBWYXIxLCB5ID0gVmFyMiwgZmlsbCA9IHZhbHVlKSkgKw0KICAgICAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKw0KICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gIiNmZjU3NTciLCBoaWdoID0gIiM0MmZmMmEiLCBtaWQgPSAiZ3JleTk1IiwgbWlkcG9pbnQgPSAwLCBsaW1pdCA9IGMoLTEsIDEpKSArDQogICAgICB0aGVtZV9taW5pbWFsKCkgKw0KICAgICAgbGFicygNCiAgICAgICAgdGl0bGUgPSBwYXN0ZSgiQ29ycmVsYXRpb24gSGVhdG1hcCAoUGFydGljaXBhbnQiLCBwYXJ0aWNpcGFudF9pZCwgIikiKSwNCiAgICAgICAgeCA9ICIiLA0KICAgICAgICB5ID0gIiINCiAgICAgICkgKw0KICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCiAgICANCiAgICAjIFN0b3JlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggYW5kIGhlYXRtYXANCiAgICByZXN1bHRzW1thcy5jaGFyYWN0ZXIocGFydGljaXBhbnRfaWQpXV0gPC0gbGlzdCgNCiAgICAgIGNvcnJlbGF0aW9uX21hdHJpeCA9IGNvcl9tYXRyaXgsDQogICAgICBoZWF0bWFwID0gaGVhdG1hcA0KICAgICkNCiAgfQ0KICANCiAgIyBSZXR1cm4gdGhlIHJlc3VsdHMgbGlzdA0KICByZXR1cm4ocmVzdWx0cykNCn0NCg0KYGBgDQoNCiMjIyBTaW5nbGUgQ29ycmVsYXRpb24gSGVhdG1hcCBFeGFtcGxlDQpgYGB7cn0NCg0KIyBFeGFtcGxlIFVzYWdlDQpwYXJ0aWNpcGFudF9pZHMgPC0gYygyLCA0LCAxMikNCmNvcnJfcmVzdWx0cyA8LSBnZW5lcmF0ZV9jb3JyTWF0cml4KHBhcnRpY2lwYW50X2lkcywgY29uKQ0KDQojIFZpZXcgaGVhdG1hcCBmb3IgcGFydGljaXBhbnQgMg0KY29ycl9yZXN1bHRzW1siMiJdXSRoZWF0bWFwDQoNCiMgTGV0cyB5b3Ugc2VlIHRoZSByYXcgbnVtZXJpYyBpbnB1dHMNCmNvcnJfcmVzdWx0c1tbIjEyIl1dJGNvcnJlbGF0aW9uX21hdHJpeCANCg0KYGBgDQojIyMgTXVsdGlwbGUgQ29ycmVsYXRpb24gSGVhdG1hcCBFeGFtcGxlIChUaGlzIENvZGUgQ2FuIGJlIFJ1biBVbi1FZGl0ZWQpDQotIExldHMgeW91IGNvbXBhcmUgMiBwYXJ0aWNpcGFudHMgcXVpY2tseSBpZGVhbGx5LCBidXQgY2FuIGJlIHNjYWxlZCB1cCB0byBncmFiIHBsb3RzIGVuIG1hc3NlDQotIFNjYWxlcyBWZXJ0aWNhbGx5IGRlcGVuZGFudCBvbiB0aGUgbnVtYmVyIG9mIHBhcnRpY2lwYW50cyBmb3Igb3JnYW5pemF0aW9uDQpgYGB7cn0NCiMgQWRqdXN0IHRoZW1lcyBvZiBoZWF0bWFwcyBpbiBjb3JyX3Jlc3VsdHMNCmZvciAoaSBpbiBzZXFfYWxvbmcoY29ycl9yZXN1bHRzKSkgew0KICBjb3JyX3Jlc3VsdHNbW2ldXSRoZWF0bWFwIDwtIGNvcnJfcmVzdWx0c1tbaV1dJGhlYXRtYXAgKyB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDgpDQp9DQoNCiMgRXh0cmFjdCBhbmQgY29tYmluZSBoZWF0bWFwcw0KY29tYmluZWRfcGxvdCA8LSB3cmFwX3Bsb3RzKA0KICBsYXBwbHkoY29ycl9yZXN1bHRzLCBmdW5jdGlvbih4KSB4JGhlYXRtYXApLA0KICBucm93ID0gbGVuZ3RoKGNvcnJfcmVzdWx0cykNCikgKw0KICBwbG90X2xheW91dChndWlkZXMgPSAiY29sbGVjdCIpICsNCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIkNvcnJlbGF0aW9uIEhlYXRtYXBzIEFjcm9zcyBQYXJ0aWNpcGFudHMiKQ0KDQojIERpc3BsYXkgdGhlIGNvbWJpbmVkIHBsb3QNCmNvbWJpbmVkX3Bsb3QNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmFjdGl2aXR5X2NsdXN0ZXJpbmcgPC0gZnVuY3Rpb24ocGFydGljaXBhbnRfaWQsIGNvbiwgayA9IDMsIC4uLikgew0KICAjIFN0ZXAgMTogUXVlcnkgdGhlIGRhdGFiYXNlIGZvciB0aGUgcGFydGljaXBhbnQncyBhY3Rpdml0eSBkYXRhDQogIHF1ZXJ5IDwtIHBhc3RlMCgiU0VMRUNUICogRlJPTSBnZXRfcGFydGljaXBhbnRfYWN0aXZpdHlfZGF0YSgiLCBwYXJ0aWNpcGFudF9pZCwgIik7IikNCiAgYWN0aXZpdHlfZGF0YSA8LSBkYkdldFF1ZXJ5KGNvbiwgcXVlcnkpDQogIA0KICAjIEVuc3VyZSBkYXRhIGlzIG5vdCBlbXB0eQ0KICBpZiAobnJvdyhhY3Rpdml0eV9kYXRhKSA9PSAwKSB7DQogICAgc3RvcChwYXN0ZSgiTm8gYWN0aXZpdHkgZGF0YSBhdmFpbGFibGUgZm9yIHBhcnRpY2lwYW50IiwgcGFydGljaXBhbnRfaWQpKQ0KICB9DQoNCiAgIyBTdGVwIDI6IFNlbGVjdCBzcGVjaWZpZWQgdmFyaWFibGVzIGR5bmFtaWNhbGx5DQogIHZhcnMgPC0gZW5xdW9zKC4uLikNCiAgY2x1c3RlcmluZ19kYXRhIDwtIGFjdGl2aXR5X2RhdGEgJT4lDQogICAgc2VsZWN0KCEhIXZhcnMpICU+JQ0KICAgIG5hLm9taXQoKQ0KDQogICMgU2NhbGUgdGhlIGRhdGEgZm9yIGNsdXN0ZXJpbmcNCiAgc2NhbGVkX2RhdGEgPC0gc2NhbGUoY2x1c3RlcmluZ19kYXRhKQ0KDQogICMgU3RlcCAzOiBQZXJmb3JtIGstbWVhbnMgY2x1c3RlcmluZw0KICBzZXQuc2VlZCgxMjMpICMgRm9yIHJlcHJvZHVjaWJpbGl0eQ0KICBrbWVhbnNfcmVzdWx0IDwtIGttZWFucyhzY2FsZWRfZGF0YSwgY2VudGVycyA9IGssIG5zdGFydCA9IDI1KQ0KDQogICMgQWRkIG51bWVyaWMgY2x1c3RlciBsYWJlbHMgdG8gdGhlIG9yaWdpbmFsIGRhdGENCiAgYWN0aXZpdHlfZGF0YSA8LSBhY3Rpdml0eV9kYXRhICU+JQ0KICAgIGZpbHRlcihjb21wbGV0ZS5jYXNlcyhzZWxlY3QoLiwgISEhdmFycykpKSAlPiUNCiAgICBtdXRhdGUoY2x1c3RlciA9IGttZWFuc19yZXN1bHQkY2x1c3RlcikNCg0KICAjIFN0ZXAgNDogQ29tcGFyZSBnbHVjb3NlIGxldmVscyBhY3Jvc3MgY2x1c3RlcnMgKGlmIGdsdWNvc2UgaXMgc2VsZWN0ZWQpDQogIGlmICgiZ2x1Y29zZV92YWx1ZV9tZ2RsIiAlaW4lIG5hbWVzKGFjdGl2aXR5X2RhdGEpKSB7DQogICAgZ2x1Y29zZV9jb21wYXJpc29uIDwtIGFjdGl2aXR5X2RhdGEgJT4lDQogICAgICBncm91cF9ieShjbHVzdGVyKSAlPiUNCiAgICAgIHN1bW1hcmlzZSgNCiAgICAgICAgYXZnX2dsdWNvc2UgPSBtZWFuKGdsdWNvc2VfdmFsdWVfbWdkbCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgc2RfZ2x1Y29zZSA9IHNkKGdsdWNvc2VfdmFsdWVfbWdkbCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgY291bnQgPSBuKCkNCiAgICAgICkNCiAgfSBlbHNlIHsNCiAgICBnbHVjb3NlX2NvbXBhcmlzb24gPC0gTlVMTA0KICB9DQoNCiAgIyBTdGVwIDU6IFZpc3VhbGl6YXRpb24gb2YgY2x1c3RlcnMNCiAgIyBJZiBtb3JlIHRoYW4gMiB2YXJpYWJsZXMgYXJlIHVzZWQsIHBsb3QgdGhlIGZpcnN0IHR3bw0KICBwbG90X3ZhcnMgPC0gbmFtZXMoY2x1c3RlcmluZ19kYXRhKVsxOjJdDQogIGNsdXN0ZXJfcGxvdCA8LSBnZ3Bsb3QoYWN0aXZpdHlfZGF0YSwgYWVzKHggPSAhIXN5bShwbG90X3ZhcnNbMV0pLCB5ID0gISFzeW0ocGxvdF92YXJzWzJdKSwgY29sb3IgPSBmYWN0b3IoY2x1c3RlcikpKSArDQogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNywgc2l6ZSA9IDMpICsNCiAgICBsYWJzKA0KICAgICAgdGl0bGUgPSBwYXN0ZSgiQ2x1c3RlcmluZyAoUGFydGljaXBhbnQiLCBwYXJ0aWNpcGFudF9pZCwgIikiKSwNCiAgICAgIHggPSBwbG90X3ZhcnNbMV0sDQogICAgICB5ID0gcGxvdF92YXJzWzJdLA0KICAgICAgY29sb3IgPSAiQ2x1c3RlciINCiAgICApICsNCiAgICB0aGVtZV9taW5pbWFsKCkNCg0KICAjIFJldHVybiByZXN1bHRzDQogIGxpc3QoDQogICAgY2x1c3Rlcl9zdW1tYXJ5ID0gZ2x1Y29zZV9jb21wYXJpc29uLA0KICAgIGNsdXN0ZXJfcGxvdCA9IGNsdXN0ZXJfcGxvdCwNCiAgICBhY3Rpdml0eV9kYXRhX3dpdGhfY2x1c3RlcnMgPSBhY3Rpdml0eV9kYXRhDQogICkNCn0NCg0KYGBgDQoNCiMjIyBEeW5hbWljIENsdXN0ZXJpbmcgRnVuY3Rpb24gZm9yIGFjdGl2aXR5IGRhdGEgKGdsdWNvc2UgdnMgbWFnbml0dWRlIHBpY3R1cmVkKQ0KLSBUaGUgVmFyaWFibGVzIGNhbiBiZSBhZGp1c3RlZCB0byB1c2UgYW55IG9mIHRoZSByZWxhdGlvbnNoaXBzIGxpc3RlZCBwcmlvciBmb3IgdGhlIG51bWVyaWMgZGF0YQ0KLSBUaGUgY2x1c3RlcnMgYXJlIG1hZGUgdGhyb3VnaCBLLW1lYW5zIGNsdXN0ZXJpbmcgYW5kIHdvcmtzIHdpdGggMiBvciBtb3JlIHZhcmlhYmxlcyBhdCBhIHRpbWUNCmBgYHtyfQ0KY2x1c3Rlcl9yZXN1bHRzIDwtIGFjdGl2aXR5X2NsdXN0ZXJpbmcoNCwgY29uLCBrID0gMywgYXZlcmFnZV9ociwgZ2x1Y29zZV92YWx1ZV9tZ2RsICkNCg0KIyBWaWV3IGdsdWNvc2UgY29tcGFyaXNvbiAoaWYgYXBwbGljYWJsZSkNCmNsdXN0ZXJfcmVzdWx0cyRjbHVzdGVyX3N1bW1hcnkNCg0KIyBWaXN1YWxpemUgY2x1c3RlcmluZw0KY2x1c3Rlcl9yZXN1bHRzJGNsdXN0ZXJfcGxvdA0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KcGVha19hbmFseXplIDwtIGZ1bmN0aW9uKHBhcnRpY2lwYW50X2lkLCBjb24sIHRocmVzaG9sZCwgcmVjb3Zlcnlfd2luZG93ID0gMykgew0KICAjIFF1ZXJ5IGFjdGl2aXR5IGRhdGEgZm9yIHRoZSBwYXJ0aWNpcGFudA0KICBxdWVyeSA8LSBwYXN0ZTAoIlNFTEVDVCAqIEZST00gZ2V0X3BhcnRpY2lwYW50X2FjdGl2aXR5X2RhdGEoIiwgcGFydGljaXBhbnRfaWQsICIpOyIpDQogIGFjdGl2aXR5X2RhdGEgPC0gZGJHZXRRdWVyeShjb24sIHF1ZXJ5KQ0KICANCiAgIyBFbnN1cmUgZGF0YSBpcyBub3QgZW1wdHkNCiAgaWYgKG5yb3coYWN0aXZpdHlfZGF0YSkgPT0gMCkgew0KICAgIHN0b3AocGFzdGUoIk5vIGFjdGl2aXR5IGRhdGEgYXZhaWxhYmxlIGZvciBwYXJ0aWNpcGFudCIsIHBhcnRpY2lwYW50X2lkKSkNCiAgfQ0KICANCiAgIyBJZGVudGlmeSBwZWFrcyB3aGVyZSBhY3Rpdml0eV9pbnRlbnNpdHlfc2NvcmUgZXhjZWVkcyB0aGUgdGhyZXNob2xkDQogIGFjdGl2aXR5X3BlYWtzIDwtIGFjdGl2aXR5X2RhdGEgJT4lDQogICAgZmlsdGVyKGFjdGl2aXR5X2ludGVuc2l0eV9zY29yZSA+IHRocmVzaG9sZCkgJT4lDQogICAgYXJyYW5nZShhY3Rpdml0eV9kYXRldGltZSkgJT4lDQogICAgbXV0YXRlKA0KICAgICAgcGVha19pZCA9IGN1bXN1bShjKFRSVUUsIGRpZmYoYXMubnVtZXJpYyhhY3Rpdml0eV9kYXRldGltZSkpID4gcmVjb3Zlcnlfd2luZG93ICogMzYwMCkpDQogICAgKQ0KICANCiAgIyBBbmFseXplIGdsdWNvc2UgbGV2ZWxzIHdpdGhpbiB0aGUgcmVjb3Zlcnkgd2luZG93IGZvciBlYWNoIHBlYWsNCiAgcmVjb3ZlcnlfYW5hbHlzaXMgPC0gYWN0aXZpdHlfcGVha3MgJT4lDQogICAgZ3JvdXBfYnkocGVha19pZCkgJT4lDQogICAgc3VtbWFyaXNlKA0KICAgICAgcGVha190aW1lID0gbWluKGFjdGl2aXR5X2RhdGV0aW1lKSwNCiAgICAgIHBlYWtfaW50ZW5zaXR5ID0gbWF4KGFjdGl2aXR5X2ludGVuc2l0eV9zY29yZSkNCiAgICApICU+JQ0KICAgIHJvd3dpc2UoKSAlPiUNCiAgICBtdXRhdGUoDQogICAgICByZWNvdmVyeV9nbHVjb3NlID0gbGlzdCgNCiAgICAgICAgYWN0aXZpdHlfZGF0YSAlPiUNCiAgICAgICAgICBmaWx0ZXIoDQogICAgICAgICAgICBhY3Rpdml0eV9kYXRldGltZSA+PSBwZWFrX3RpbWUgJiANCiAgICAgICAgICAgIGFjdGl2aXR5X2RhdGV0aW1lIDw9IChwZWFrX3RpbWUgKyBhcy5kaWZmdGltZShyZWNvdmVyeV93aW5kb3csIHVuaXRzID0gImhvdXJzIikpDQogICAgICAgICAgKSAlPiUNCiAgICAgICAgICBzZWxlY3QoYWN0aXZpdHlfZGF0ZXRpbWUsIGdsdWNvc2VfdmFsdWVfbWdkbCwgYXZlcmFnZV9ociwgYWN0aXZpdHlfaW50ZW5zaXR5X3Njb3JlKQ0KICAgICAgKQ0KICAgICkNCiAgDQogICMgUHJlcGFyZSBkYXRhIGZvciBQbG90bHkgdGltZWxpbmUNCiAgYWxsX3RyYWNlcyA8LSBsaXN0KCkNCiAgDQogIGZvciAoaSBpbiBzZXFfbGVuKG5yb3cocmVjb3ZlcnlfYW5hbHlzaXMpKSkgew0KICAgIHJlY292ZXJ5X2RhdGEgPC0gcmVjb3ZlcnlfYW5hbHlzaXMkcmVjb3ZlcnlfZ2x1Y29zZVtbaV1dDQogICAgDQogICAgIyBBZGQgZ2x1Y29zZSB0cmFjZSB3aXRoIGR5bmFtaWMgdGl0bGUNCiAgICBhbGxfdHJhY2VzW1tsZW5ndGgoYWxsX3RyYWNlcykgKyAxXV0gPC0gbGlzdCgNCiAgICAgIHggPSByZWNvdmVyeV9kYXRhJGFjdGl2aXR5X2RhdGV0aW1lLA0KICAgICAgeSA9IHJlY292ZXJ5X2RhdGEkZ2x1Y29zZV92YWx1ZV9tZ2RsLA0KICAgICAgbmFtZSA9IHBhc3RlKCJQZWFrIiwgcmVjb3ZlcnlfYW5hbHlzaXMkcGVha19pZFtpXSwgIi0gR2x1Y29zZSIpLA0KICAgICAgdHlwZSA9ICJzY2F0dGVyIiwNCiAgICAgIG1vZGUgPSAibGluZXMiLA0KICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIHdpZHRoID0gNiksICMgVGhpY2tlciBibHVlIGxpbmUNCiAgICAgIHNtb290aGluZyA9IDEuOCAjIE9wdGlvbmFsIHNtb290aGluZyBmb3IgY3VydmVzDQogICAgKQ0KICAgIA0KICAgICMgQWRkIGhlYXJ0IHJhdGUgdHJhY2UNCiAgICBhbGxfdHJhY2VzW1tsZW5ndGgoYWxsX3RyYWNlcykgKyAxXV0gPC0gbGlzdCgNCiAgICAgIHggPSByZWNvdmVyeV9kYXRhJGFjdGl2aXR5X2RhdGV0aW1lLA0KICAgICAgeSA9IHJlY292ZXJ5X2RhdGEkYXZlcmFnZV9ociwNCiAgICAgIG5hbWUgPSBwYXN0ZSgiUGVhayIsIHJlY292ZXJ5X2FuYWx5c2lzJHBlYWtfaWRbaV0sICItIEhlYXJ0IFJhdGUiKSwNCiAgICAgIHR5cGUgPSAic2NhdHRlciIsDQogICAgICBtb2RlID0gImxpbmVzIiwNCiAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJnYmEoMjU1LCAwLCAwLCAwLjIpIikgIyBUcmFuc3BhcmVudCByZWQNCiAgICApDQogICAgDQogICAgIyBBZGQgYWN0aXZpdHkgaW50ZW5zaXR5IHRyYWNlDQogICAgYWxsX3RyYWNlc1tbbGVuZ3RoKGFsbF90cmFjZXMpICsgMV1dIDwtIGxpc3QoDQogICAgICB4ID0gcmVjb3ZlcnlfZGF0YSRhY3Rpdml0eV9kYXRldGltZSwNCiAgICAgIHkgPSByZWNvdmVyeV9kYXRhJGFjdGl2aXR5X2ludGVuc2l0eV9zY29yZSwNCiAgICAgIG5hbWUgPSBwYXN0ZSgiUGVhayIsIHJlY292ZXJ5X2FuYWx5c2lzJHBlYWtfaWRbaV0sICItIEFjdGl2aXR5IEludGVuc2l0eSIpLA0KICAgICAgdHlwZSA9ICJzY2F0dGVyIiwNCiAgICAgIG1vZGUgPSAibGluZXMiLA0KICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAicmdiYSgwLCAxMjgsIDAsIDAuMykiKSAjIFRyYW5zcGFyZW50IGdyZWVuDQogICAgKQ0KICB9DQoNCiAgIyBDcmVhdGUgc2xpZGVyIHN0ZXBzIGZvciBpbnRlcmFjdGl2aXR5DQogIHN0ZXBzIDwtIGxhcHBseShzZXFfbGVuKG5yb3cocmVjb3ZlcnlfYW5hbHlzaXMpKSwgZnVuY3Rpb24oaSkgew0KICAgIGxpc3QoDQogICAgICBtZXRob2QgPSAidXBkYXRlIiwNCiAgICAgIGFyZ3MgPSBsaXN0KA0KICAgICAgICBsaXN0KHZpc2libGUgPSBjKHJlcChGQUxTRSwgKGkgLSAxKSAqIDMpLCBUUlVFLCBUUlVFLCBUUlVFLCByZXAoRkFMU0UsIChucm93KHJlY292ZXJ5X2FuYWx5c2lzKSAtIGkpICogMykpKSwNCiAgICAgICAgbGlzdCh0aXRsZSA9IHBhc3RlKCJSZWNvdmVyeSBBZnRlciBQZWFrIiwgcmVjb3ZlcnlfYW5hbHlzaXMkcGVha19pZFtpXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIoQWN0aXZpdHkgSW50ZW5zaXR5OiIsIHJlY292ZXJ5X2FuYWx5c2lzJHBlYWtfaW50ZW5zaXR5W2ldLCAiKSIpKQ0KICAgICAgKSwNCiAgICAgIGxhYmVsID0gcGFzdGUoIlBlYWsiLCByZWNvdmVyeV9hbmFseXNpcyRwZWFrX2lkW2ldKQ0KICAgICkNCiAgfSkNCg0KICAjIEJ1aWxkIHRoZSBQbG90bHkgZmlndXJlDQogIGZpZyA8LSBwbG90X2x5KCkNCiAgDQogIGZvciAodHJhY2UgaW4gYWxsX3RyYWNlcykgew0KICAgIGZpZyA8LSBmaWcgJT4lIGFkZF90cmFjZSh4ID0gdHJhY2UkeCwgeSA9IHRyYWNlJHksIHR5cGUgPSB0cmFjZSR0eXBlLCBtb2RlID0gdHJhY2UkbW9kZSwgbmFtZSA9IHRyYWNlJG5hbWUsIGxpbmUgPSB0cmFjZSRsaW5lKQ0KICB9DQogIA0KICBmaWcgPC0gZmlnICU+JQ0KICAgIGxheW91dCgNCiAgICAgIHRpdGxlID0gcGFzdGUoIkdsdWNvc2UgYW5kIEhlYXJ0IFJhdGUgUmVjb3ZlcnkgQWZ0ZXIgUGVha3MgKFBhcnRpY2lwYW50IiwgcGFydGljaXBhbnRfaWQsICIpIiksDQogICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiVGltZSIpLA0KICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlZhbHVlIiksDQogICAgICBhdXRvc2l6ZSA9IFRSVUUsDQogICAgICBzbGlkZXJzID0gbGlzdCgNCiAgICAgICAgbGlzdCgNCiAgICAgICAgICBhY3RpdmUgPSAwLA0KICAgICAgICAgIHN0ZXBzID0gc3RlcHMNCiAgICAgICAgKQ0KICAgICAgKQ0KICAgICkgJT4lDQogIGNvbmZpZygNCiAgICByZXNwb25zaXZlID0gVFJVRSAjIEVuYWJsZXMgcmVzcG9uc2l2ZW5lc3MgZm9yIGR5bmFtaWMgcmVzaXppbmcNCiAgKQ0KICANCiAgcmV0dXJuKGZpZykNCn0NCg0KDQpgYGANCg0KIyMjIFBlYWsgQW5hbHlzaXMgdXNpbmcgcHJvY2VkdXJhbCBncmFwaCBnZW5lcmF0aW9uIGJhc2VkIG9mZiBhIHBhcnRpY2lwYW50IGlucHV0DQotIEEgcGFydGljaXBhbnQgY2FuIGJlIGFuYWx5emVkIHdpdGggYSBjaG9zZW4gdGhyZXNob2xkIG9mIHRoZWlyIGFjdGl2aXR5IHNjb3JlDQogIC0gUGVha3MgYmFzZWQgb2ZmIHRoaXMgdGhyZXNob2xkIHdpbGwgYmUgY29udmVydGVkIHRvIGdyYXBocyB3aXRoIGEgd2luZG93IGZyb20gc3RhcnQgb2YgdGhlIHBlYWsgdG8gYSBjaG9zZW4gZHVyYXRpb24gaW4gaG91cnMNCi0gVGhlIGdlbmVyYXRlZCBncmFwaCB3b3JrcyBiZXN0IGluIFIgd2hlcmUgdGhlIEhUTUwgY2FuIGJlIHZpZXdlZCBpbiBhIGNsZWFuZXIgZm9ybWF0Lg0KICAtIFRoZSBwbG90bHkgcGFja2FnZSBhbGxvd3Mgc2Nyb2xsaW5nIGJldHdlZW4gdGhlIHBlYWtzIHRvIGNvbnZlbmllbnRseSBzZWUgbm90YWJsZSByZWdpb25zDQpgYGB7ciBwZWFrLWFuYWx5c2lzLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OSwgZWNobz1GQUxTRSwgb3V0LndpZHRoPSc3NSUnfQ0KDQojIEV4YW1wbGUgVXNhZ2UgKHVzZXMgcGF0aWVudCwgZGF0YSBjb25uZWN0aW9uLCBhY3R2aXR5IHRocmVzaG9sZCwgYW5kIGEgcmVjb3Zlcnkgd2luZG93IGluIGhvdXJzKQ0KcGVha19yZXN1bHRzIDwtIHBlYWtfYW5hbHl6ZSg0LCBjb24sIHRocmVzaG9sZCA9IDk1LCByZWNvdmVyeV93aW5kb3cgPSA0KQ0KDQojIFZpZXcgdGhlIGludGVyYWN0aXZlIHBsb3QNCnBlYWtfcmVzdWx0cw0KYGBgDQoNCg==